// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Mono.Cecil;
using Mono.Linker.Tests.Cases.Expectations.Assertions;
using Mono.Linker.Tests.Extensions;

namespace Mono.Linker.Tests.TestCasesRunner
{
    public partial class AssemblyChecker
    {
        static bool SkipKeptItemsValidation(IMemberDefinition member)
        {
            // Skip verification of type metadata for compiler generated members (we don't currently need it yet)

            // Compiler generated members can't be annotated with `Kept` attributes directly
            // For some of them we have special attributes (backing fields for example), but it's impractical to define
            // special attributes for all types of compiler generated members (there are quite a few of them and they're
            // going to change/increase over time).
            // So we're effectively disabling Kept validation on compiler generated members

            if (IsCompilerGeneratedMember(member))
                return true;

            do
            {
                if (ResultChecker.HasActiveSkipKeptItemsValidationAttribute(member))
                    return true;
            }
            while ((member = member.DeclaringType) != null);

            return false;

            static bool IsCompilerGeneratedMember(IMemberDefinition member)
            {
                // Top-level methods are generated with names like
                // <<Main>$>g__MethodName|0_1(). While the names are generated by
                // the compiler, don't consider the method to be compiler-generated
                // for the purpose of Kept validation, because they are attributable
                // in source like any other method.
                if (member is MethodDefinition method && method.Name.Contains("<Main>$"))
                    return false;

                if (IsCompilerGeneratedMemberName(member.Name))
                    return true;

                if (member.DeclaringType != null)
                    return IsCompilerGeneratedMember(member.DeclaringType);

                return false;
            }

            static bool IsCompilerGeneratedMemberName(string memberName)
            {
                return memberName.Length > 0 && memberName[0] == '<';
            }
        }

        static bool IsDelegateBackingFieldsType(TypeDefinition type) => type.Name == "<>O";

        static bool IsPrivateImplementationDetailsType(TypeDefinition type) =>
            string.IsNullOrEmpty(type.Namespace) && type.Name.StartsWith("<PrivateImplementationDetails>");
    }
}
